/*
 *  RESTful DDS is a prototyping effort to demonstrate how DDS could be combined
 *  with HTTP clients, extending the realm of pub/sub distribution to true wide
 *  area networking.
 *
 *  Copyright (C) 2009 PrismTech Ltd.
 *  reinier.torenbeek@gmail.com
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License Version 3 dated 29 June 2007, as published by the
 *  Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with restful-dds; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package track;

import java.util.HashMap;

/**
 *
 */
public final class ObjectLocation_topicWrapper {
	private static HashMap<DDS.DomainParticipant, DDS.Listener> listenerMap = new HashMap<DDS.DomainParticipant, DDS.Listener>();
	private static HashMap<DDS.DomainParticipant, java.lang.Integer> statusMaskMap = new HashMap<DDS.DomainParticipant, java.lang.Integer>();

	private ObjectLocation_topicWrapper() {
	}

	@SuppressWarnings("serial")
	public static class WrapperException extends Exception {
		private final String m_reason;
		private final DDS.Entity m_entity;
		private final String m_sourceType;
		private final String m_method;
		private final int m_returnValue;
		private final String m_wrapper;

		protected WrapperException() {
			m_reason = null;
			m_entity = null;
			m_sourceType = null;
			m_method = null;
			m_returnValue = DDS.RETCODE_OK.value;
			m_wrapper = null;
		}

		public WrapperException(final String reason, final DDS.Entity entity,
				final String sourceType, final String method,
				final int returnValue, final String wrapper) {
			m_reason = reason;
			m_entity = entity;
			m_sourceType = sourceType;
			m_method = method;
			m_returnValue = returnValue;
			m_wrapper = wrapper;
		}

		public String getSourceType() {
			return m_sourceType;
		}

		public String getReason() {
			return m_reason;
		}

		public DDS.Entity getEntity() {
			return m_entity;
		}

		public String getMethod() {
			return m_method;
		}

		public int getReturnValue() {
			return m_returnValue;
		}

		public String getWrapper() {
			return m_wrapper;
		}

		@Override
		public String getMessage() {
			final StringBuilder message = new StringBuilder();

			message.append(String.format("[%s] call %s.%s failed.", m_wrapper,
					m_sourceType, m_method));

			if (m_returnValue != DDS.RETCODE_OK.value) {
				message.append(" ReturnValue: ");
				message.append(m_returnValue);
			}

			if (m_reason != null) {
				message.append(" Reason: ");
				message.append(m_reason);
			}

			return message.toString();
		}

	}

	@SuppressWarnings("serial")
	public static class ContainerWrapperException extends WrapperException {
		private final static String LINE_SEPARATOR = System
				.getProperty("line.separator"); //$NON-NLS-1$
		private final java.util.List<WrapperException> m_exceptions;

		public ContainerWrapperException(
				final java.util.List<WrapperException> exceptions) {
			m_exceptions = exceptions;
		}

		public java.util.List<WrapperException> getExceptions() {
			return java.util.Collections.unmodifiableList(m_exceptions);
		}

		@Override
		public String getMessage() {
			final StringBuilder message = new StringBuilder();

			for (WrapperException exception : m_exceptions) {
				message.append(exception.getMessage());
				message.append(LINE_SEPARATOR);
			}

			return message.toString();
		}
	}

	/*
	 * Create the DDS.Topic using the provided DDS.DomainParticipant.
	 * @throws WrapperException
	 */
	public synchronized static DDS.Topic start(
			DDS.DomainParticipant domainParticipant) throws WrapperException {
		DDS.Topic topic = null;

		final DDS.TopicDescription description = domainParticipant
				.lookup_topicdescription("track_ObjectLocation_topic");

		if (description != null) {
			if (description instanceof DDS.Topic) {
				return (DDS.Topic) description;
			} else {
				throw new WrapperException("Invalid Topic type",
						domainParticipant, "DDS.DomainParticipant",
						"lookup_topicdescription", DDS.RETCODE_OK.value,
						"track.ObjectLocation_topicWrapper.start()");
			}
		}

		DDS.TopicQosHolder tQoS = new DDS.TopicQosHolder();
		getTopicQoS(domainParticipant, tQoS);

		track.ObjectLocationTypeSupport TS = getTopicTypeSupport();

		int registerTypeOp = TS.register_type(domainParticipant,
				"::track::ObjectLocation");

		if (registerTypeOp != DDS.RETCODE_OK.value) {
			throw new WrapperException(null, null, "DDS.TypeSupport",
					"register_type", registerTypeOp,
					"track.ObjectLocation_topicWrapper.start()");
		}

		if (listenerMap.get(domainParticipant) == null) {
			topic = domainParticipant.create_topic(
					"track_ObjectLocation_topic", "::track::ObjectLocation",
					tQoS.value, null, DDS.ANY_STATUS.value);
		} else {
			DDS.TopicListener topicListener = (DDS.TopicListener) (listenerMap
					.get(domainParticipant));
			int statusMask = ((java.lang.Integer) (statusMaskMap
					.get(domainParticipant))).intValue();

			topic = domainParticipant.create_topic(
					"track_ObjectLocation_topic", "::track::ObjectLocation",
					tQoS.value, topicListener, statusMask);
		}

		if (topic == null) {
			throw new WrapperException("Null returned", domainParticipant,
					"DDS.DomainParticipant", "create_topic",
					DDS.RETCODE_OK.value,
					"track.ObjectLocation_topicWrapper.start()");
		}

		return topic;
	}

	/**
	 *
	 */
	public static DDS.Topic start(DDS.Publisher publisher)
			throws WrapperException {
		DDS.DomainParticipant participant = publisher.get_participant();
		return start(participant);
	}

	/**
	 *
	 */
	public static DDS.Topic start(DDS.Subscriber subscriber)
			throws WrapperException {
		DDS.DomainParticipant participant = subscriber.get_participant();
		return start(participant);
	}

	/**
	 *
	 */
	public static DDS.Topic start(DDS.DataReader dataReader)
			throws WrapperException {
		DDS.DomainParticipant participant = dataReader.get_subscriber()
				.get_participant();
		return start(participant);
	}

	/**
	 *
	 */
	public static DDS.Topic start(DDS.DataWriter dataWriter)
			throws WrapperException {
		DDS.DomainParticipant participant = dataWriter.get_publisher()
				.get_participant();
		return start(participant);
	}

	/**
	 *
	 */
	public static DDS.Topic start(DDS.ContentFilteredTopic topic)
			throws WrapperException {
		DDS.DomainParticipant participant = topic.get_participant();
		return start(participant);
	}

	/*
	 * Delete the DDS.Topic using the DDS.DomainParticipant provided in start().
	 * @throws WrapperException
	 */
	public synchronized static void stop(DDS.DomainParticipant participant)
			throws WrapperException {
		DDS.Topic topic = null;
		int retcode = DDS.RETCODE_OK.value;

		final DDS.TopicDescription description = participant
				.lookup_topicdescription("track_ObjectLocation_topic");

		if (description != null) {
			if (description instanceof DDS.Topic) {
				topic = (DDS.Topic) description;
			} else {
				throw new WrapperException("Invalid Topic type", participant,
						"DDS.DomainParticipant", "lookup_topicdescription",
						DDS.RETCODE_OK.value,
						"track.ObjectLocation_topicWrapper.stop()");
			}
		} else {
			throw new WrapperException("Null returned", participant,
					"DDS.DomainParticipant", "lookup_topicdescription",
					DDS.RETCODE_OK.value,
					"track.ObjectLocation_topicWrapper.stop()");
		}

		retcode = participant.delete_topic(topic);
		if (retcode != DDS.RETCODE_OK.value) {
			throw new WrapperException(null, participant,
					"DDS.DomainParticipant", "delete_topic", retcode,
					"track.ObjectLocation_topicWrapper.stop()");
		}
	}

	/**
	 *
	 */
	private static void getTopicQoS(DDS.DomainParticipant participant,
			DDS.TopicQosHolder qos) {
		//Get default Topic Qos settings
		participant.get_default_topic_qos(qos);

		qos.value.durability.kind = DDS.DurabilityQosPolicyKind.VOLATILE_DURABILITY_QOS;
		qos.value.durability_service.history_kind = DDS.HistoryQosPolicyKind.KEEP_LAST_HISTORY_QOS;
		qos.value.durability_service.history_depth = 1;
		qos.value.durability_service.max_instances = -1;
		qos.value.durability_service.max_samples = -1;
		qos.value.durability_service.max_samples_per_instance = -1;
		qos.value.durability_service.service_cleanup_delay = new DDS.Duration_t(
				0, 0);
		qos.value.deadline.period = new DDS.Duration_t(
				DDS.DURATION_INFINITE_SEC.value,
				DDS.DURATION_INFINITE_NSEC.value);

		qos.value.latency_budget.duration = new DDS.Duration_t(0, 0);
		qos.value.ownership.kind = DDS.OwnershipQosPolicyKind.SHARED_OWNERSHIP_QOS;
		qos.value.liveliness.kind = DDS.LivelinessQosPolicyKind.AUTOMATIC_LIVELINESS_QOS;
		qos.value.liveliness.lease_duration = new DDS.Duration_t(
				DDS.DURATION_INFINITE_SEC.value,
				DDS.DURATION_INFINITE_NSEC.value);
		qos.value.reliability.kind = DDS.ReliabilityQosPolicyKind.BEST_EFFORT_RELIABILITY_QOS;
		qos.value.reliability.max_blocking_time = new DDS.Duration_t(0,
				100000000);
		qos.value.transport_priority.value = 0;
		qos.value.lifespan.duration = new DDS.Duration_t(
				DDS.DURATION_INFINITE_SEC.value,
				DDS.DURATION_INFINITE_NSEC.value);
		qos.value.destination_order.kind = DDS.DestinationOrderQosPolicyKind.BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS;
		qos.value.history.kind = DDS.HistoryQosPolicyKind.KEEP_LAST_HISTORY_QOS;
		qos.value.history.depth = 1;
		qos.value.resource_limits.max_instances = -1;
		qos.value.resource_limits.max_samples = -1;
		qos.value.resource_limits.max_samples_per_instance = -1;
	}

	/**
	 *
	 */
	private static track.ObjectLocationTypeSupport getTopicTypeSupport() {
		return new track.ObjectLocationTypeSupport();
	}

}
